/*******************************************************************************
 * @file    bsp_uart.c
 * @brief   Universal Asynchronous Receiver/Transmitter
 *
 * @version 1.0.0
 *******************************************************************************
 * @license Refer License or other description Docs
 * @author  Felix
 ******************************************************************************/
#include "cpu/bsp_uart.h"
#ifndef USE_NO_UART
#include "uart.h"
#endif

/****
Global Variables
****/

/****
Local Variables
****/
static user_callback_t sLEUART0CallBack = NULL;
static user_callback_t sLEUART1CallBack = NULL;
#ifndef USE_NO_UART
static user_callback_t sUART0CallBack = NULL;
static user_callback_t sUART1CallBack = NULL;
static user_callback_t sUART2CallBack = NULL;
static user_callback_t sUART3CallBack = NULL;
#endif
/*******************************************************************************
 * @brief UART IRQ handler
 *
 * When the signal frame is detected by the UART, this interrupt routine will
 * invoke the callback.
 *
 ******************************************************************************/
void LpUart0_IRQHandler(void)
{
    if(LPUart_GetStatus(M0P_LPUART0, LPUartRC)){
        LPUart_ClrStatus(M0P_LPUART0, LPUartRC);
        if(sLEUART0CallBack != NULL){
            sLEUART0CallBack(LPUart_ReceiveData(M0P_LPUART0));
        }
    }
}

void LpUart1_IRQHandler(void)
{
    if(LPUart_GetStatus(M0P_LPUART1, LPUartRC)){
        LPUart_ClrStatus(M0P_LPUART1, LPUartRC);
        if(sLEUART1CallBack != NULL){
            sLEUART1CallBack(LPUart_ReceiveData(M0P_LPUART1));
        }
    }
}

void Uart0_IRQHandler(void)
{
    if(Uart_GetStatus(M0P_UART0, UartRC)){
        Uart_ClrStatus(M0P_UART0, UartRC);
        if(sUART0CallBack != NULL){
            sUART0CallBack(Uart_ReceiveData(M0P_UART0));
        }
    }
}

void Uart1_IRQHandler(void)
{
    if(Uart_GetStatus(M0P_UART1, UartRC)){
        Uart_ClrStatus(M0P_UART1, UartRC);
        if(sUART1CallBack != NULL){
            sUART1CallBack(Uart_ReceiveData(M0P_UART1));
        }
    }
}

void Uart2_IRQHandler(void)
{
    if(Uart_GetStatus(M0P_UART2, UartRC)){
        Uart_ClrStatus(M0P_UART2, UartRC);
        if(sUART2CallBack != NULL){
            sUART2CallBack(Uart_ReceiveData(M0P_UART2));
        }
    }
}

void Uart3_IRQHandler(void)
{
    if(Uart_GetStatus(M0P_UART3, UartRC)){
        Uart_ClrStatus(M0P_UART3, UartRC);
        if(sUART3CallBack != NULL){
            sUART3CallBack(Uart_ReceiveData(M0P_UART3));
        }
    }
}

/**
 * LPUART config
 */
static void BSP_LPUART_Init(BSP_UART_IDX comIdx, uint8_t pari, uint32_t baudrate)
{
    M0P_LPUART_TypeDef *uart = M0P_LPUART0;
    stc_lpuart_cfg_t uartInit;
    IRQn_Type enIrq = LPUART0_IRQn;

    DDL_ZERO_STRUCT(uartInit);

    /* UART initialize values */
    uartInit.enRunMode = LPUartMskMode1;
    uartInit.enStopBit = LPUart1bit;
    uartInit.enMmdorCk = LPUartDataOrAddr;
    uartInit.stcBaud.u32Baud = baudrate;
    uartInit.stcBaud.enSclkDiv = LPUartMsk4Or8Div;
    uartInit.stcBaud.u32Sclk = Sysctrl_GetPClkFreq();

    /* UART CLK */
    if(baudrate <= 9600){
        uartInit.stcBaud.enSclkSel = LPUartMskRcl;
        uartInit.stcBaud.u32Sclk = 38400;
    } else {
        uartInit.stcBaud.enSclkSel = LPUartMskPclk;
    }

    if(BSP_LPUART1 == comIdx){
        uart = M0P_LPUART1;
        enIrq = LPUART1_IRQn;
    }

    switch(pari){
    case UART_PARI_EVEN:
        uartInit.enMmdorCk = LPUartEven;
        uartInit.enRunMode = LPUartMskMode3;
        break;
    case UART_PARI_ODD:
        uartInit.enMmdorCk = LPUartOdd;
        uartInit.enRunMode = LPUartMskMode3;
        break;
    case UART_PARI_NONE:
    default:
        break;
    }

    LPUart_Init(uart, &uartInit);

    /* Clear All IRQ */
    LPUart_ClrIsr(uart);
    /* Enable RX IRQ */
    LPUart_EnableIrq(uart, LPUartRxIrq);
    EnableNvic(enIrq, IrqLevel3, TRUE);

    return;
}

#ifndef USE_NO_UART
static void BSP_UART_Init(BSP_UART_IDX comIdx, uint8_t pari, uint32_t baudrate)
{
    M0P_UART_TypeDef *uart = M0P_UART0;
    stc_uart_cfg_t uartInit;
    IRQn_Type enIrq = UART0_2_IRQn;

    DDL_ZERO_STRUCT(uartInit);

    /* UART initialize values */
    uartInit.enRunMode = UartMskMode1;
    uartInit.enStopBit = UartMsk1bit;
    uartInit.enMmdorCk = UartMskDataOrAddr;
    uartInit.stcBaud.u32Baud = baudrate;
    uartInit.stcBaud.enClkDiv = UartMsk8Or16Div;
    uartInit.stcBaud.u32Pclk = Sysctrl_GetPClkFreq();

    switch(comIdx)
    {
    case BSP_UART1:
        uart = M0P_UART1;
        enIrq = UART1_3_IRQn;
        break;
    case BSP_UART2:
        uart = M0P_UART2;
        enIrq = UART0_2_IRQn;
        break;
    case BSP_UART3:
        uart = M0P_UART3;
        enIrq = UART1_3_IRQn;
        break;
    default:
        break;
    }

    switch(pari){
    case UART_PARI_EVEN:
        uartInit.enMmdorCk = UartMskEven;
        uartInit.enRunMode = UartMskMode3;
        break;
    case UART_PARI_ODD:
        uartInit.enMmdorCk = UartMskOdd;
        uartInit.enRunMode = UartMskMode3;
        break;
    case UART_PARI_NONE:
    default:
        break;
    }

    Uart_Init(uart, &uartInit);

    /* Clear All IRQ */
    Uart_ClrIsr(uart);

    /* Enable RX IRQ */
    Uart_EnableIrq(uart, UartRxIrq);
    EnableNvic(enIrq, IrqLevel3, TRUE);

    return;
}
#endif
/****
Global Functions
****/

/**
 * UART Initialization
 *
 * This function use the default settings to initialize UART.
 * We assume that does not modify the default settings.
 *
 */
void BSP_UartInit(const BSP_UART_TypeDef *ptr)
{
    uint32_t baudrate = 9600;
    en_sysctrl_peripheral_gate_t clock = SysctrlPeripheralLpUart0;
    bool  isLeuart = false;

    if(ptr->idx == BSP_LPUART0 || ptr->idx == BSP_LPUART1){
        isLeuart = true;
    } else {
#ifndef USE_NO_UART
        clock = SysctrlPeripheralUart1;
#endif
    }

    switch(ptr->idx){
    case BSP_LPUART0:
        sLEUART0CallBack = ptr->cb;
        clock = SysctrlPeripheralLpUart0;
        break;
    case BSP_LPUART1:
        sLEUART1CallBack = ptr->cb;
        clock = SysctrlPeripheralLpUart1;
        break;
#ifndef USE_NO_UART
    case BSP_UART0:
        sUART0CallBack = ptr->cb;
        clock  = SysctrlPeripheralUart0;
        break;
    case BSP_UART1:
        sUART1CallBack = ptr->cb;
        clock = SysctrlPeripheralUart1;
        break;
    case BSP_UART2:
        sUART2CallBack = ptr->cb;
        clock  = SysctrlPeripheralUart2;
        break;
    case BSP_UART3:
        sUART3CallBack = ptr->cb;
        clock = SysctrlPeripheralUart3;
        break;
#endif
    default:
        break;
    }

    /* Enabling UART clocks */
    Sysctrl_SetPeripheralGate(clock, TRUE);
    baudrate = BSP_UartGetBaudRate(ptr->bdtype);

    if(true == isLeuart) {
        BSP_LPUART_Init(ptr->idx, ptr->pri, baudrate);
    } else {
#ifndef USE_NO_UART
        BSP_UART_Init(ptr->idx, ptr->pri, baudrate);
#endif
    }
}

void BSP_UartDeInit(const BSP_UART_TypeDef *ptr)
{
    /* TODO: */
}

/**
 * UART RX IRQ enable or disable
 */
void BSP_UartRxEnable(BSP_UART_IDX comIdx, bool enable)
{
    switch(comIdx){
    case BSP_LPUART0:
        if(enable){
            LPUart_EnableIrq(M0P_LPUART0, LPUartRxIrq);
        } else {
            LPUart_DisableIrq(M0P_LPUART0, LPUartRxIrq);
        }
        break;
    case BSP_LPUART1:
        if(enable){
            LPUart_EnableIrq(M0P_LPUART1, LPUartRxIrq);
        } else {
            LPUart_DisableIrq(M0P_LPUART1, LPUartRxIrq);
        }
        break;
#ifndef USE_NO_UART
    case BSP_UART0:
        if(enable){
            Uart_EnableIrq(M0P_UART0, UartRxIrq);
        } else {
            Uart_DisableIrq(M0P_UART0, UartRxIrq);
        }
        break;
    case BSP_UART1:
        if(enable){
            Uart_EnableIrq(M0P_UART1, UartRxIrq);
        } else {
            Uart_DisableIrq(M0P_UART1, UartRxIrq);
        }
        break;
    case BSP_UART2:
        if(enable){
            Uart_EnableIrq(M0P_UART2, UartRxIrq);
        } else {
            Uart_DisableIrq(M0P_UART2, UartRxIrq);
        }
        break;
    case BSP_UART3:
        if(enable){
            Uart_EnableIrq(M0P_UART3, UartRxIrq);
        } else {
            Uart_DisableIrq(M0P_UART3, UartRxIrq);
        }
        break;
#endif
    }
}

/**
 * Send data to UART
 */
void BSP_UartSend(BSP_UART_IDX comIdx, const uint8_t *data, uint32_t len)
{
    uint32_t idx = 0;

    for(idx = 0; idx < len; idx++){
        switch(comIdx){
        case BSP_LPUART0:
            if (LPUart_SendData(M0P_LPUART0, *data++) != Ok)
                LPUart_ClrIsr(M0P_LPUART0);//SoftReset();
            break;
        case BSP_LPUART1:
            LPUart_SendData(M0P_LPUART1, *data++);
            break;
#ifndef USE_NO_UART
        case BSP_UART0:
            Uart_SendDataPoll(M0P_UART0, *data++);
            break;
        case BSP_UART1:
            Uart_SendDataPoll(M0P_UART1, *data++);
            break;
        case BSP_UART2:
            Uart_SendDataPoll(M0P_UART2, *data++);
            break;
        case BSP_UART3:
            Uart_SendDataPoll(M0P_UART3, *data++);
            break;
#endif
        }
    }
}

uint32_t BSP_UartGetBaudRate(uint8_t bdtype)
{
    uint32_t baudrate = 9600;
    switch(bdtype)
    {
    case UART_BRATE_1200:
        baudrate = 1200U;
        break;
    case UART_BRATE_2400:
        baudrate = 2400U;
        break;
    case UART_BRATE_4800:
        baudrate = 4800U;
        break;
    case UART_BRATE_9600:
        baudrate = 9600U;
        break;
    case UART_BRATE_19200:
        baudrate = 19200U;
        break;
    case UART_BRATE_38400:
        baudrate = 38400U;
        break;
    case UART_BRATE_57600:
        baudrate = 57600U;
        break;
    case UART_BRATE_115200:
        baudrate = 115200U;
        break;
    default:
        break;
    }

    return baudrate;
}
